﻿using System;
using Microsoft.SPOT;

using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using GTI = Gadgeteer.Interfaces;

namespace Gadgeteer.Modules.GHIElectronics
{
    // -- CHANGE FOR MICRO FRAMEWORK 4.2 --
    // If you want to use Serial, SPI, or DaisyLink (which includes GTI.SoftwareI2C), you must do a few more steps
    // since these have been moved to separate assemblies for NETMF 4.2 (to reduce the minimum memory footprint of Gadgeteer)
    // 1) add a reference to the assembly (named Gadgeteer.[interfacename])
    // 2) in GadgeteerHardware.xml, uncomment the lines under <Assemblies> so that end user apps using this module also add a reference.

    /// <summary>
    /// A Thermocouple module for Microsoft .NET Gadgeteer
    /// </summary>
    /// <example>
    /// <para>The following code example uses a <see cref="Thermocouple"/> object to read the temperature of an attached thermocouple 
    /// and the module chip's temperature, printing those vaules to the output window.</para>
    /// <code>
    ///using Microsoft.SPOT;
    ///
    ///using GTM = Gadgeteer.Modules;
    ///
    ///namespace TestApp
    ///{
    ///    public partial class Program
    ///    {
    ///        void ProgramStarted()
    ///        {
    ///            short c;
    ///            short f;
    ///            byte i;
    ///
    ///            c = therm.GetExternalTemp_Celsius();
    ///            f = therm.GetExternalTemp_Fahrenheit();
    ///            i = therm.GetInternalTemp_Celsius();
    ///
    ///            Debug.Print("C: " + c);
    ///            Debug.Print("F: " + f);
    ///            Debug.Print("I: " + i);
    ///        }
    ///    }
    ///}
    /// </code>
    /// </example>
    public class Thermocouple : GTM.Module
    {
        private GTI.DigitalInput _miso;
        private GTI.DigitalOutput _clk;
        private GTI.DigitalOutput _cs;

        private const int ERROR_NOCONECT = 0x01;
        private const int ERROR_SHORTGND = 0x02;
        private const int ERROR_SHORTVCC = 0x04;

        // Note: A constructor summary is auto-generated by the doc builder.
        /// <summary></summary>
        /// <param name="socketNumber">The socket that this module is plugged in to.</param>
        public Thermocouple(int socketNumber)
        {
            Socket socket = Socket.GetSocket(socketNumber, true, this, null);

            socket.EnsureTypeIsSupported(new char[] { 'X', 'Y' }, this);

            _miso = new GTI.DigitalInput(socket, Socket.Pin.Three, GTI.GlitchFilterMode.Off, GTI.ResistorMode.PullUp, this);
            _clk = new GTI.DigitalOutput(socket, Socket.Pin.Four, false, this);
            _cs = new GTI.DigitalOutput(socket, Socket.Pin.Five, true, this);
        }

        private uint ReadData()
        {
            int bitCount;
            uint data = 0;

            _cs.Write(false);
            {
                for (bitCount = 31; bitCount >= 0; bitCount--)
                {
                    _clk.Write(true);

                    if (_miso.Read())
                    {
                        data |= (uint)(1 << bitCount);
                    }

                    _clk.Write(false);
                }
            }
            _cs.Write(true);

            return data;
        }

        /// <summary>
        /// Gets the external temperature using the attached thermocouple.
        /// </summary>
        /// <returns>Returns the external temperature, in Celsius.</returns>
        public short GetExternalTemp_Celsius()
        {
            uint value = ReadData();
            short temperature = 0;
            byte[] data = new byte[4];
            data[0] = (byte)(value >> 24);
            data[1] = (byte)(value >> 16);
            data[2] = (byte)(value >> 8);
            data[3] = (byte)(value >> 0);
            temperature = (short)(((data[1]) | (data[0] << 8)));
            temperature = (short)(temperature >> 4);
            return temperature;
        }

        /// <summary>
        /// Gets the external temperature using the attached thermocouple.
        /// </summary>
        /// <returns>Returns the external temperature, in Fahrenheit.</returns>
        public short GetExternalTemp_Fahrenheit()
        {
            return (short)((GetExternalTemp_Celsius() * 1.8) + 32);
        }

        /// <summary>
        /// Gets the internal temperature of the chip.
        /// </summary>
        /// <returns></returns>
        public byte GetInternalTemp_Celsius()
        {
            uint value = ReadData();
            return (byte)((value >> 8) & 0xFF); // get byte 2
        }

    }
}
